﻿#ifndef PLCCLIENTBASE_H
#define PLCCLIENTBASE_H
#include <QDataStream>
#include <QMap>
#include <QModbusDataUnit>
#include "ComCommon.h"


//需要在main中添加这几行使得序列化到ini生效
//qRegisterMetaTypeStreamOperators<PLCClientConfig>("PLCClientConfig");
//qRegisterMetaTypeStreamOperators<PLCRequestData>("PLCRequestData");
//qRegisterMetaTypeStreamOperators<ModbusValue>("ModbusValue");
enum PLCClientType{
    PCT_ModbusTcp = 0,
    PCT_ModbusRtu,
    PCT_MC,
    PCT_FX,
    PCT_FinsTcp,
    PCT_FinsUdp,
    PCT_HostLink,
    PCT_TaiDa,
    PCT_WeiKong,
    PCT_SerialRelay,
    PCT_TcpRelay,
};

struct PLCClientConfig{
    QString name;//客户端名
    PLCClientType type;//客户端类型
    int writeSpace;//循环写入时间，设置为PLC的响应时间
    int serverID;//站号
    bool isReadConstant;//是否持续读取
    int readSpace;//读取间隔
    QMap<QString, PLCRequestData> mapReadCfgs;//读取配置,读取配置的地址需为连续地址
    ComClientConfig comConfig;//通讯配置
    PLCClientConfig() : name(""), type(PCT_ModbusTcp), writeSpace(20), serverID(0),
        isReadConstant(false), readSpace(40){
    }

    PLCClientConfig(QString name, PLCClientType type, int writeSpace, int serverID, int readSpace, bool isReadConstant){
        this->name = name;
        this->type = type;
        this->readSpace = readSpace;
        this->isReadConstant = isReadConstant;
        this->writeSpace = writeSpace;
        this->serverID = serverID;
    }
    ~PLCClientConfig()
    {
    }
    friend QDataStream &operator<<(QDataStream &out, const PLCClientConfig &config)
    {
        out << config.name
            << config.type
            << config.writeSpace
            << config.serverID
            << config.isReadConstant
            << config.readSpace
            << config.comConfig;
        out << config.mapReadCfgs.size();
        for(auto cfgKey : config.mapReadCfgs.keys()){
            out << cfgKey << config.mapReadCfgs.value(cfgKey);
        }
        return out;

    }
    friend QDataStream &operator>>(QDataStream &in, PLCClientConfig &config)
    {
        in >> config.name
            >> config.type
            >> config.writeSpace
            >> config.serverID
            >> config.isReadConstant
            >> config.readSpace
            >> config.comConfig;
        int count;
        in >> count;
        config.mapReadCfgs.clear();
        for(int i = 0; i < count; ++i){
            PLCRequestData cfg;
            QString key;
            in >> key >> cfg;
            config.mapReadCfgs.insert(key, cfg);
        }
        return in;
    }
};
Q_DECLARE_METATYPE(PLCClientConfig)

class PLCClientBase: public QObject
{
    Q_OBJECT
public:
    explicit PLCClientBase(QString name, QObject *parent = nullptr);
    virtual ~PLCClientBase();

    static QMap<ComState, QString> mapPLCStateText;
    static QMap<PLCClientType, QString> mapPLCClientTypeText;
    static void initPLCClientBaseStaticVar() {
        mapPLCStateText = {
                           {CS_Invalid,tr("<font color=\'red\'>不可用</font>")},
                           {CS_Connected,tr("<font color=\'green\'>连接成功</font>")},
                           {CS_UnConnected,tr("<font color=\'yellow\'>断开连接</font>")}
                            };
        mapPLCClientTypeText = {
            {PCT_ModbusTcp,tr("ModbusTcp")},
            {PCT_ModbusRtu,tr("ModbusRtu")},
            {PCT_MC,tr("MC")},
            {PCT_FX,tr("FX")},
            {PCT_FinsTcp,tr("FinsTcp")},
            {PCT_FinsUdp,tr("FinsUdp")},
            {PCT_HostLink,tr("HostLink")},
            {PCT_TaiDa,tr("TaiDa")},
            {PCT_WeiKong,tr("WeiKong")},
            {PCT_SerialRelay,tr("SerialRelay")},
            {PCT_TcpRelay,tr("TcpRelay")}
        };
    }

    void setConfig(const PLCClientConfig &plcConfig);
    ComState getPLCState() const {return mPLCState;}

signals:
    void sigStateChanged(const ComState& state);
    void sigErrOccur(const QString& msg);
    void sigData(const PLCRequestData& requestData);

public slots:
    virtual void onInit();
    virtual void onInitReadConfig(){}
    virtual void onQuit();
    virtual void onRead(const PLCRequestData& data);
    virtual void onWrite(const PLCRequestData& data);
    virtual void onPLCConfigChanged(const PLCClientConfig& plcConfig);
    virtual void reconnect();

protected:
    virtual void sendReadData(const PLCRequestData& data) = 0;
    virtual void sendWriteData(const PLCRequestData& data) = 0;
    virtual void initTimer();
    virtual void stopTimer();
    virtual void initCom() = 0;
    void setPLCState(const ComState& state);

private:
    virtual void timerEvent(QTimerEvent *event) override;
    void onProcessRequestData();
    void onStateChanged(const ComState& state);
public:
    PLCClientConfig mConfig;
protected:
    QString mName;
    ComState mPLCState = CS_Invalid;
    PLCRequestData mCurDataRead;
    PLCRequestData mCurDataWrite;

private:
    int mReadTimerID = -1;
    int mReconnectTimerID = -1;
    int mProcessRequestTimerID = -1;
    QList<PLCRequestData>  mLstRequestData;
};

#endif // PLCCLIENTBASE_H
